﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Utils.Common;
using ZK.BLL.Config;
using ZK.Entity;
using ZK.Pack;

namespace ZK.BLL.MainExecute
{
    public class CIJExecute
    {
        private static volatile CIJExecute instance;
        public static CIJExecute Instance
        {
            get
            {
                if (instance == null)
                {

                    if (instance == null)
                    {
                        instance = new CIJExecute();
                    }

                }
                return instance;
            }
        }
 

        public bool IsRunning = false;

        TcpCIJPrinter tcpClient;
        public PrintData CurrPrintData { get; set; }

        public delegate void DelCompleted(PrintData printData);
        public event DelCompleted CompletedEvent;

        public Queue<SendData> queue = new Queue<SendData>();
        private object syncLocal = new object();
        BitArray bitArray;
        public int Index = 0;

        private string _logoName = "";
        private string _productName = "";



        //07
        //图案模块
        //0000
        //x
        //0000
        //y
        //00
        //旋转 0°；图案反色：否
        //01
        //操作类型：发送图片
        //01
        //文件名字节数
        //42
        //文件名:“B”
        //0006
        //原始宽度
        //0009
        //原始高度
        //FA 18 61 FA
        //图片数据
        //18 61 F8


        private string checkCode = string.Empty;

        public bool Start(string logoName, string productName, string ip, int port)
        {
            try
            {
                _logoName = logoName;
                _productName = productName;

                tcpClient = new TcpCIJPrinter(ip, port);
                tcpClient.Open();
                tcpClient.EventHandlerReceived += TcpClient_EventHandlerReceived; ;
                Thread.Sleep(100);

            }
            catch (Exception ex)
            {

                LogHelper.LogError(ex.Message);
                if (tcpClient != null) tcpClient.Close();
                return false;
            }
            return IsRunning = true;
        }

        private void TcpClient_EventHandlerReceived(object sender, EventArgs e)
        {

            try
            {
                byte [] revStr = (byte[]) sender ;
                lock (syncLocal)
                {
                    Index++;

                    if (bitArray != null && bitArray.Count > Index)
                    {
                        Console.WriteLine(revStr[3].ToString());

                        if (revStr.Length >= 4)
                        {
                            if (revStr[3] == 0)
                            {
                                bitArray.Set(Index, true);
                            }
                            else
                            {
                                if (revStr[3].ToString() == "18")
                                {
                                    LogHelper.LogError($"喷码机返回错误码:{revStr[3].ToString()}(未开机)");
                                }
                                else {
                                    LogHelper.LogError($"喷码机返回错误码:{revStr[3].ToString()}");
                                }
                                bitArray.Set(Index, false);
                            }
                        }

                    }
                    if (queue.Count > 0)
                    {
                        Thread.Sleep(100);
                        var sendData = queue.Dequeue();
                        tcpClient.WriteData(strToToHexByte(sendData.Msg));
                    }


                }
            }
            catch { }
        }

        public bool Stop()
        {
            try
            {

                tcpClient.EventHandlerReceived -= TcpClient_EventHandlerReceived;
                tcpClient.Close();
            }
            catch
            {
                return false;
            }

            IsRunning = false;
            return true;
        }

     


        public void ReSend(PrintData printdata)
        {
           var cijTemplate = CIJTemplateBLL.Instance.GetByTemplateName(printdata.TemplateName);
            if(cijTemplate==null)
            {
                LogHelper.LogError($"模板{printdata.TemplateName}不存在,请检查模板设置！");
                return;
            }

            string paramspace = "".PadLeft(SystemConfig.GetConfig().SystemInfoEntity.ParamSpace, ' ');
            List<SendData> dataList = new List<SendData>();
            //dataList.Add(new SendData() { Command = SystemConfig.GetConfig().SystemInfoEntity.TemplateName, Msg = SelectTemplate(SystemConfig.GetConfig().SystemInfoEntity.TemplateName) });

            int currentX = 0;
         
            string imageData = SendLogoData(printdata.CustomerName, out int imageWith);
            currentX += imageWith;
            string p1Str = printdata.ProductName + printdata.ModelNo;
            string txtP1 = GetTextStr(currentX + cijTemplate.P1OffSetX, cijTemplate.P1OffSetY, p1Str, cijTemplate.P1Font);
            currentX += cijTemplate.P1OffSetX+ p1Str.Length * cijTemplate.P1Unit;  
            string batchNo = printdata.UserPrintName + printdata.BatchNo;
            string txtP2 = GetTextStr(currentX + cijTemplate.P2OffSetX, cijTemplate.P2OffSetY, batchNo, cijTemplate.P2Font);
            currentX += cijTemplate.P2OffSetX+(printdata.UserPrintName + printdata.BatchNo).Length * cijTemplate.P2Unit ;
            string txtP3 = GetTextStr(currentX + cijTemplate.P3OffSetX, cijTemplate.P3OffSetY, printdata.Other, cijTemplate.P3Font);
           
            dataList.Add(new SendData() { Command = "CMD1", Msg = GetLastSendData(imageData, txtP1, txtP2, txtP3).Replace(" ", "").ToLower() });
            dataList.Add(new SendData() { Command = "CMD2", Msg = LoadPrinter() });
             //dataList.Add(new SendData() { Command = "CMD3", Msg = PrintAction() });
            WriteCommands(printdata, dataList);
        }


        public Bitmap CreateImage(PrintData printdata)
        {
            string fileName = ConfigBase.LogoImg + "\\" + printdata.CustomerName + ".bmp";

            if (!File.Exists(fileName))
            {
                LogHelper.LogError($"LOGO图片[{printdata.CustomerName}.bmp]不存在！");
                return null;
            }

            var cijTemplate = CIJTemplateBLL.Instance.GetByTemplateName(printdata.TemplateName);
            if (cijTemplate == null)
            {
                LogHelper.LogError($"模板[{printdata.TemplateName}]不存在！");
                return null;
            }
            Bitmap bmpLogo = new Bitmap(fileName);

           var bmpP1 = TextBitmap.TextToBitmap(printdata.ProductName+ printdata.ModelNo, new Font("黑体", (float)cijTemplate.P1Unit, FontStyle.Regular), Color.Black, Color.White, cijTemplate.P1OffSetX, cijTemplate.P1OffSetY);
           var bmpP2 = TextBitmap.TextToBitmap(printdata.UserPrintName + printdata.BatchNo, new Font("黑体", (float)cijTemplate.P2Unit, FontStyle.Regular), Color.Black, Color.White, cijTemplate.P2OffSetX, cijTemplate.P2OffSetY);
           var bmpP3 = TextBitmap.TextToBitmap(printdata.Other, new Font("黑体", (float)cijTemplate.P3Unit, FontStyle.Regular), Color.Black, Color.White, cijTemplate.P3OffSetX, cijTemplate.P3OffSetY);

           Bitmap bitmap =  TextBitmap.ImageShiftY(bmpLogo, bmpP1, bmpP2, bmpP3);
           bmpLogo.Dispose();
           bmpP1.Dispose();
           bmpP2.Dispose();
           bmpP3.Dispose();
           return bitmap;
        }
        /// <summary>
        /// 图片数据
        /// </summary>
        /// <param name="imageName"></param>
        /// <param name="paramName"></param>
        /// <returns></returns>
        public string SendLogoData(string imageName, out int imageWith)
        {


            imageWith = 0;
            string fileName = ConfigBase.LogoImg + "\\" + imageName + ".bmp";

            if (!File.Exists(fileName))
            {
                LogHelper.LogError("LOGO图片不存在");
                return string.Empty;
            }
            using (Bitmap bmp = new Bitmap(fileName))
            {
                imageWith = bmp.Width;
              return   Image2Data(bmp , imageName);
            }
        }

        private string Image2Data(Bitmap bmp, string imageName)
        {
       
            int width = bmp.Width;
            int height = bmp.Height;

            int _with = 0;
            int _height = 0;
            _height = height;
            _with = width;
         
            int _offset = 0;

            string imageData = GetImageStr(bmp, _offset, _with, _height);

            if (string.IsNullOrEmpty(imageData))
            {
                return string.Empty;
            }

            string imagehex = StrToHEXStr(imageName);

            string data = $"07 0000 0000 00 01 {imagehex.Split(' ').Length.ToString("X2")} {imagehex} {_with.ToString("X4")} {_height.ToString("X4")} {imageData}";

            string imageStr = data.Replace(" ", "").ToLower();
            return data;
        }
         
       

        private string GetImageStr(Bitmap bmp, int offset, int _width, int _height)
        {

            string str = string.Empty;
            BitArray bitArray = null;
            //Bitmap bitmap = new Bitmap(width, height);

            for (int y = 0; y < _height; y++)
            {
                for (int x = offset; x < offset + _width; x++)
                {

                    int n = ((y * _width) + x) % 8;

                    if (n % 8 == 0)
                    {
                        bitArray = new BitArray(8, false);
                    }
                    bool b = false;

                    Color srcColor = bmp.GetPixel(x, y);
                    byte temp = (byte)(srcColor.R * .299 + srcColor.G * .587 + srcColor.B * .114);
                    b = temp < 255 ? true : false;

                    bitArray.Set(7 - n, b);
                    if (n == 7 || x == offset + _width - 1 && y == _height - 1)
                    {
                        int val = BitArray2Int(bitArray);
                        str += val.ToString("X2");

                    }
                }
            }

            return str;
        }


        private string GetTextStr(int offsetX,int offsetY, string txt ,string fontName= "CJK24X24L", int spacing=3,int blod=0)
        {

            string pos = offsetX.ToString("X4") + offsetY.ToString("X4");

            string txthex = StrToHEXStr(txt);

            string fonthex = StrToHEXStr(fontName);

            string val = $"01 {pos} 00 {spacing.ToString("X2")} {blod.ToString("X2")} {fonthex.Split(' ').Length.ToString("X2")} {fonthex} {txthex.Split(' ').Length.ToString("X2")} {txthex}";

            return val;
        }


        int BitArray2Int(BitArray ba)
        {
            int ret = 0;
            for (int i = 0; i < ba.Length; i++)
            {
                if (ba.Get(i))
                {
                    ret |= (1 << i);
                }
            }
            return ret;
        }





        public void WriteCommands(PrintData printData, List<SendData> lists)
        {

            Stopwatch stopWatch = new Stopwatch();
            queue.Clear();
            lists.ForEach(s =>
            {
                queue.Enqueue(s);
            });
            stopWatch.Start();
            lock (syncLocal)
            {
                bitArray = new BitArray(lists.Count, false);
                Index = -1;
                var sendData = queue.Dequeue();
                tcpClient.WriteData(strToToHexByte(sendData.Msg));
            }

            Task.Factory.StartNew(() =>
            {
                int n = 0;
                while (n < 500 && Index < bitArray.Count - 1)
                {
                    n++;
                    Thread.Sleep(10);
                }
                bool result = true;
                lock (syncLocal)
                {
                    for (int i = 0; i < bitArray.Count; i++)
                    {
                        if (!bitArray[i])
                        {
                            result = false;
                        }
                    }
                }
                stopWatch.Stop();
                if (!result)
                {
                    LogHelper.LogError($"发送失败或超时({stopWatch.ElapsedMilliseconds}ms)");
                }
                else
                {

                    printData.Id = PrintDataBLL.Instance.GetNewID();
                    printData.PrintDate = DateTime.Now;
                    PrintDataBLL.Instance.Insert(printData);

                    LogHelper.LogDebug($"发送成功({stopWatch.ElapsedMilliseconds}ms)");
                }
            });
        }




        private string GetDataWithCheckCode(string sendData)
        {
            sendData = sendData.Replace(" ", "");

            int val = 0;

            int n = sendData.Length / 2;

            for (int i = 0; i < n; i++)
            {
                val += Convert.ToInt32(sendData[2 * i].ToString() + sendData[2 * i + 1].ToString(), 16);
            }

            string checkCode = (256 - val % 256).ToString("X2");
            //正数的补码等于本身 
            if (checkCode == "100")
            {
                // 负数的补码等于反码 + 1
                checkCode = "00";
            }
            if(sendData.Length>20)
            LogHelper.LogDebug("校验码："+ checkCode);
            return sendData + checkCode;

        }


        public string StrToHEXStr(string str)
        {

            char[] vs = str.ToCharArray();

            string b = "";
            byte[] c = new byte[vs.Length];

            for (int i = 0; i < vs.Length; i++)
            {
                c[i] = (byte)vs[i];
            }

            foreach (var bt in c)
            {
                b += bt.ToString("X2") + " ";
            }

            return b.Trim(' ');
        }



        public string GetLastSendData(string imageData, string txtP1, string txtP2, string txtP3)
        {
            string start = "1B 02 00 1C";

            string end = "1B 03";

            string dataname = StrToHEXStr(CIJSystemConfig.GetConfig().SystemInfoEntity.TemplateName);
            string datanameLen = dataname.Split(' ').Length.ToString("X2");
            string lenStr = $"{datanameLen}{dataname}04{ imageData}{txtP1}{txtP2}{txtP3}".ToLower().Replace(" ", "");
            int dataLen = lenStr.Length / 2;
            string val = $"{start} {dataLen.ToString("X6")} {dataname.Split(' ').Length.ToString("X2")} {dataname} 04 {imageData} {txtP1} {txtP2} {txtP3} {end}";
            return GetDataWithCheckCode(val);
        }

        //public string LoadSendData()
        //{
        //    string start = "1B 02 00 1E";

        //    string end = "1B 03";

        //    string dataname = StrToHEXStr(CIJSystemConfig.GetConfig().SystemInfoEntity.TemplateName);
        //    string val = $"{start} {dataname.Split(' ').Length.ToString("X2")} {dataname} {end}";

        //    return GetDataWithCheckCode(val);
        //}

        public string LoadPrinter()
        {
            return GetDataWithCheckCode("1B 02 00 01 1B 03");
        }

        public string PrintAction()
        {

            return GetDataWithCheckCode("1B 02 00 13 1B 03");

        }


        public static string UnHex(string s)
        {
            s = s.Replace(" ", "").Trim().ToUpper();
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
                buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);

            return Encoding.UTF8.GetString(buffer);
        }


        private static byte[] strToToHexByte(string hexString)

        {
            
            hexString = hexString.Replace(" ", "");

            if ((hexString.Length % 2) != 0)
            {
                hexString += "0";
                LogHelper.LogError("内容错误");
            }
             
     
            byte[] returnBytes = new byte[hexString.Length / 2];

            for (int i = 0; i < returnBytes.Length; i++)

                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);

            return returnBytes;

        }
    }
}